home *** CD-ROM | disk | FTP | other *** search
/ SGI Hot Mix 17 / Hot Mix 17.iso / HM17_SGI / research / lib / recon3.pro < prev    next >
Encoding:
Text File  |  1997-07-08  |  17.9 KB  |  434 lines

  1. ; $Id: recon3.pro,v 1.11 1997/01/30 23:48:45 dan Exp $
  2. ;
  3. ; Copyright (c) 1993-1997, Research Systems, Inc.  All rights reserved.
  4. ;       Unauthorized reproduction prohibited.
  5. ;
  6. ;+
  7. ; NAME:
  8. ;    RECON3
  9. ;
  10. ; PURPOSE:
  11. ;    This function can reconstruct a 3-dimensional data array from
  12. ;       two or more images (or projections) of an object.   For example,
  13. ;       if you placed a dark object in front of a white background and
  14. ;       then photographed it three times (each time rotating the object a
  15. ;       known amount) then these three images could be used with RECON3
  16. ;       to approximate a 3-D volumetric representation of the object.
  17. ;       RECON3 also works with translucent projections of an object.
  18. ;       RECON3 returns a 3-D byte array.   RECON3 uses the back-projection
  19. ;       method.   In medical imaging and other applications, a method
  20. ;       known as "Filtered Backprojection" is often desired.   This may
  21. ;       be accomplished here by first filtering the images as desired,
  22. ;       and then using the filtered images for the reconstruction.
  23. ;
  24. ; CATEGORY:
  25. ;    Volume Reconstruction
  26. ;
  27. ; CALLING SEQUENCE:
  28. ;       vol = RECON3(Images, Obj_Rot, Obj_Pos, Focal, Dist, $
  29. ;                    Vol_Pos, Img_Ref, Img_Mag, Vol_Size)
  30. ;
  31. ; INPUTS:
  32. ;       Images:   The images to use to reconstruct the volume.   Execution
  33. ;                 time increases linearly with more images.
  34. ;                 Data Type: 8-bit (byte) array with dimensions [x, y, n]
  35. ;                 where x is the horizontal image dimension, y is the vertical
  36. ;                 image dimension, and n is the number of images.
  37. ;
  38. ;       Obj_Rot:  The the amount the object is rotated to make it appear as
  39. ;                 it does in each image.   The object is first rotated
  40. ;                 about the X axis, then about the Y axis, and finally
  41. ;                 about the Z axis (with the object's reference point at the
  42. ;                 origin.
  43. ;                 Data Type: [3, n] Float array where Obj_Rot[0, *] is the X
  44. ;                 rotation for each image, Obj_Rot[1, *] is the Y rotation, 
  45. ;                 and Obj_Rot[2, *] is the Z rotation.
  46. ;                 
  47. ;       Obj_Pos:  The position of the the object's reference point RELATIVE to
  48. ;                 the camera lens.   The camera lens is located at the
  49. ;                 coordinate origin and points in the negative Z direction
  50. ;                 (the view up vector points in the positive Y direction).
  51. ;                 Obj_Pos should be expressed in this coordinate system.
  52. ;                 The values for Obj_Pos, Focal, Dist, and Vol_Pos should all
  53. ;                 be expressed in the same units (mm, cm, m, in, ft, etc.).
  54. ;                 Data Type: [3, n] Float array where Obj_Pos[0, *] is the X
  55. ;                 position for each image, Obj_Pos[1, *] is the Y position, 
  56. ;                 and Obj_Pos[2, *] is the Z position.   All the values in
  57. ;                 Obj_Pos[2, *] should be less than zero.
  58. ;
  59. ;       Focal:    The focal length of the lens for each image.   Focal may be
  60. ;                 set to zero to indicate a parallel image projection
  61. ;                 (infinite focal length).
  62. ;                 Data Type: Float array with n elements.
  63. ;
  64. ;       Dist:     The distance from the camera lens to the image plane (film)
  65. ;                 for each image.   Dist should be greater than Focal.
  66. ;                 Data Type: Float array with n elements.
  67. ;
  68. ;       Vol_Pos:  The two opposite corners of a cube that surrounds the object.
  69. ;                 Vol_Pos should be expressed in the object's coordinate system
  70. ;                 RELATIVE to the object's reference point.
  71. ;                 Data Type: [3, 2] Float array where Vol_Pos[*, 0] specifies
  72. ;                 one corner and Vol_Pos[*, 1] specifies the opposite corner.
  73. ;
  74. ;       Img_Ref:  The pixel location at which the object's reference point
  75. ;                 appears in each of the images.
  76. ;                 Data Type: [2, n] Int or Float array where Img_Ref[0, *] is
  77. ;                 the X coordinate for each image and Img_Ref[1, *] is the Y
  78. ;                 coordinate.
  79. ;
  80. ;       Img_Mag:  The magnification factor for each image.   This number is
  81. ;                 actually the length (in pixels) that a test object would
  82. ;                 appear in an image if it were N units long and N units
  83. ;                 distant from the camera lens.
  84. ;                 Data Type: [2, n] Int or float array where Img_Mag[0, *] is
  85. ;                 the X dimension (in pixels) of a test object for each image,
  86. ;                 and Img_Mag[1, *] is the Y dimension.   All elements in
  87. ;                 Img_Mag should be greater than or equal to 1.
  88. ;
  89. ;       Vol_Size: The size of the volume to return.   The returned volume will
  90. ;                 be a 3-D byte array with dimensions equal to Vol_Size.
  91. ;                 Execution time (and resolution) increases exponentially with
  92. ;                 larger values for Vol_Size.
  93. ;                 Data Type: Int array with 3 elements where Vol_Size[0]
  94. ;                 specifies the X dimension of the volume, Vol_Size[1] specifies
  95. ;                 the Y dimension, and Vol_Size[2] specifies the Z dimension.
  96. ;
  97. ; KEYWORD PARAMETERS:
  98. ;       CUBIC:    If set, then cubic interpolation is used.   The default is
  99. ;                 to use tri-linear interpolation, which is slightly faster.
  100. ;
  101. ;       MISSING:  The value for cells in the 3-D volume that do not map to
  102. ;                 any of the supplied images.   The Missing value is passed
  103. ;                 to the IDL "INTERPOLATE" function.
  104. ;                 Data Type: Byte.
  105. ;                 Default : 0B
  106. ;
  107. ;       MODE:     If Mode is less than zero then each cell in the 3-D volume
  108. ;                 is the MINIMUM of the corresponding pixels in the images.
  109. ;                 If Mode is greater than zero then each cell in the 3-D volume
  110. ;                 is the MAXIMUM of the corresponding pixels in the images.
  111. ;                 If Mode is equal to zero then each cell in the 3-D volume
  112. ;                 is the AVERAGE of the corresponding pixels in the images.
  113. ;                 Mode should usually be (-1) when the images contain a bright
  114. ;                 object in front of a dark background.   Mode should usually
  115. ;                 be (+1) when the images contain a dark object in front of a
  116. ;                 light background.   AVERAGE mode requires more memory since
  117. ;                 the volume array must temporarily be kept as an INT array
  118. ;                 instead of a BYTE array.
  119. ;                 Data Type: Int
  120. ;                 Default : 0 (average cells)
  121. ;
  122. ; OUTPUTS:
  123. ;    RECON3 returns a 3-D byte array containing the reconstructed object.
  124. ;
  125. ;       If the images contain low (dark) values where the object is and high
  126. ;       (bright) values where the object isn't, then Mode should be set to (+1).
  127. ;       If the above is true then the returned volume will have low values
  128. ;       where the object is, and high values where the object isn't.
  129. ;
  130. ;       If the images contain high (bright) values where the object is and low
  131. ;       (dark) values where the object isn't, then Mode should be set to (-1).
  132. ;       If the above is true then the returned volume will have high values
  133. ;       where the object is, and low values where the object isn't.
  134. ;
  135. ; RESTRICTIONS:
  136. ;       In general, the object must be CONVEX for a good reconstruction to be
  137. ;       possible.   Concave regions are not easily reconstructed.
  138. ;       An empty coffee cup, for example, would be reconstructed as if it
  139. ;       were full.
  140. ;
  141. ;    The images should show strong light/dark contrast between the object
  142. ;       and the background.
  143. ;
  144. ;       The more images the better.   Images from many different angles will
  145. ;       improve the quality of the reconstruction.   It is also important to
  146. ;       supply images that are parallel and perpendicular to any axes of
  147. ;       symmetry.   Using the coffee cup as an example, at least one image
  148. ;       should be looking through the opening in the handle.
  149. ;
  150. ;       Telephoto images are also better for reconstruction purposes than
  151. ;       wide angle images.
  152. ;
  153. ; PROCEDURE:
  154. ;    A 4x4 transformation matrix is created for each image based upon the
  155. ;       parameters Obj_Rot, Obj_Pos, Focal, Dist, and Img_Ref.   Each cell in
  156. ;       the volume is assigned a 3-D coordinate based upon the parameters
  157. ;       Vol_Pos and Vol_Size.   These coordinates are multiplied by the
  158. ;       transformation matricies to produce x,y image coordinates.   Each cell
  159. ;       in the volume is assigned a value that is the AVERAGE, MINIMUM, or
  160. ;       MAXIMUM of the image values at the x,y position (depending on Mode).
  161. ;
  162. ; EXAMPLE:
  163. ; ------------------------------------------------------------------------------
  164. ;       ; Assumptions for this example :
  165. ;       ; The object's major axis is parallel to the Z axis.
  166. ;       ; The object's reference point is at its center.
  167. ;       ; The camera lens is pointed directly at this reference point.
  168. ;       ; The reference point is 5000 mm in front of the camera lens.
  169. ;       ; The focal length of the camera lens is 200 mm.
  170. ;
  171. ;       ; If the camera is focused on the reference point, then the
  172. ;       ; distance from the lens to the camera's image plane must be
  173. ;       ;    dist = (d * f) / (d - f) =
  174. ;       ;    (5000 * 200) / (5000 - 200) = (1000000 / 4800) = 208.333 mm
  175. ;
  176. ;       ; The object is roughly 600 mm wide and 600 mm high.
  177. ;       ; The reference point appears in the exact center of each image.
  178. ;
  179. ;       ;  If the object is 600 mm high and 5000 mm distant from the camera
  180. ;       ;  lens, then the object image height must be
  181. ;       ;     hi = (h * f) / (d - f)  =
  182. ;       ;     (600 * 200) / (5000 - 200) = (120000 / 4800) = 25.0 mm
  183. ;       ;  The object image appears 200 pixels high so the final magnification
  184. ;       ;  factor is
  185. ;       ;     img_mag = (200 / 25) = 8.0
  186. ;
  187. ;       imgy = 256
  188. ;       frames = 3
  189. ;       images = Bytarr(imgx, imgy, frames, /Nozero)
  190. ;       obj_rot = Fltarr(3, frames)
  191. ;       obj_pos = Fltarr(3, frames)
  192. ;       focal = Fltarr(frames)
  193. ;       dist = Fltarr(frames)
  194. ;       vol_pos = Fltarr(3, 2)
  195. ;       img_ref = Fltarr(2, frames)
  196. ;       img_mag = Fltarr(2, frames)
  197. ;       vol_size = [40, 40, 40]
  198. ;       ; The object is 5000 mm directly in front of the camera.
  199. ;       obj_pos[0, *] =     0.0
  200. ;       obj_pos[1, *] =     0.0
  201. ;       obj_pos[2, *] = -5000.0
  202. ;       ; The focal length of the lens is constant for all the images.
  203. ;       focal[*] = 200.0
  204. ;       ; The distance from the lens to the image plane is also constant.
  205. ;       dist[*] = 208.333
  206. ;       ; The cube surrounding the object is 600 mm X 600 mm.
  207. ;       vol_pos[*, 0] = [-300.0, -300.0, -300.0]
  208. ;       vol_pos[*, 1] = [ 300.0,  300.0,  300.0]
  209. ;       ; The image reference point appears at the center of all the images.
  210. ;       img_ref[0, *] = imgx / 2
  211. ;       img_ref[1, *] = imgy / 2
  212. ;       ; The image magnification factor is constant for all images.
  213. ;       ; (The images haven't been cropped or resized).
  214. ;       img_mag[*, *] = 8.0
  215. ;       ; Only the object rotation changes from one image to the next.
  216. ;       ; Note that the object is rotated about the X axis first, then Y,
  217. ;       ; and then Z.
  218. ;       ; Create some fake images for this example.
  219. ;       images[30:160, 20:230, 0] = 255
  220. ;       images[110:180, 160:180, 0] = 180
  221. ;       obj_rot[*, 0] = [-90.0, 0.0, 0.0]
  222. ;       images[70:140, 100:130, 1] = 255
  223. ;       obj_rot[*, 1] = [-70.0, 75.0, 0.0]
  224. ;       images[10:140, 70:170, 2] = 255
  225. ;       images[80:90, 170:240, 2] = 150
  226. ;       obj_rot[*, 1] = [-130.0, 215.0, 0.0]
  227. ;       ; Reconstruct the volume.
  228. ;       vol = RECON3(images, obj_rot, obj_pos, focal, dist, vol_pos, img_ref, $
  229. ;                    img_mag, vol_size, Missing=255B, Mode=(-1))
  230. ; ------------------------------------------------------------------------------
  231. ;
  232. ; MODIFICATION HISTORY:
  233. ;     Written by:    Daniel Carr    Thu Feb  4 02:54:29 MST 1993
  234. ;    KDB - 23 Dec., 1993 - Variable dist had a conflict with Userlib
  235. ;                  function DIST and could cause compile errors.
  236. ;                  Renamed variable dist to distance.
  237. ;       Modified by:    Daniel Carr     Mon Nov 21 14:21:57 MST 1994
  238. ;          Improved performance and added CUBIC keyword.
  239. ;       Modified by:    Daniel Carr     Tue Nov 22 12:18:15 MST 1994
  240. ;          Fixed bug which affected small focal length images.
  241. ;          Improved performance again.
  242. ;-
  243.  
  244. FUNCTION RECON3, images, obj_rot, obj_pos, focal, distance, vol_pos, img_ref, $
  245.                  img_mag, vol_size, Missing=missing, Mode=mode, Cubic=cubic
  246.  
  247. ; *** Check inputs.
  248.  
  249. sz_images = Size(images)
  250. IF (sz_images[0] NE 3) THEN $
  251.    Message, 'Image array must have 3 dimensions.'
  252. frames = sz_images[3]
  253. ysize = sz_images[2]
  254. xsize = sz_images[1]
  255.  
  256. sz_obj_rot = Size(obj_rot)
  257. IF (sz_obj_rot[0] NE 2) THEN $
  258.    Message, 'Obj_Rot must be a [3, n] array.'
  259. IF (sz_obj_rot[1] NE 3) THEN $
  260.    Message, 'Obj_Rot must be a [3, n] array.'
  261. IF (sz_obj_rot[2] NE frames) THEN $
  262.    Message, 'Obj_Rot must be a [3, n] array, where n is the number of images.'
  263. obj_rot1 = Float(obj_rot)
  264.  
  265. sz_obj_pos = Size(obj_pos)
  266. IF (sz_obj_pos[0] NE 2) THEN $
  267.    Message, 'Obj_Pos must be a [3, n] array.'
  268. IF (sz_obj_pos[1] NE 3) THEN $
  269.    Message, 'Obj_Pos must be a [3, n] array.'
  270. IF (sz_obj_pos[2] NE frames) THEN $
  271.    Message, 'Obj_Pos must be a [3, n] array, where n is the number of images.'
  272. ind = Where(obj_pos[2, *] GE 0.0)
  273. IF (ind[0] GE 0) THEN $
  274.    Message, 'The object Z position must be < 0 for all images.'
  275. obj_pos1 = Float(obj_pos)
  276.  
  277. IF (N_Elements(focal) NE frames) THEN $
  278.    Message, $
  279.       'Focal must contain the same number of elements as there are images.'
  280. ind = Where(focal[*] LT 0.0)
  281. IF (ind[0] GE 0) THEN $
  282.    Message, 'Focal must be >= 0 for all images.'
  283. focal1 = Float(focal[*])
  284.  
  285. IF (N_Elements(distance) NE frames) THEN $
  286.    Message, 'Len must contain the same number of elements as Focal.'
  287. ind = Where(distance[*] LE focal[*])
  288. IF (ind[0] GE 0) THEN $
  289.    Message, 'Len must be greater than Focal for all images.'
  290. dist1 = Float(distance[*])
  291.  
  292. sz_vol_pos = Size(vol_pos)
  293. IF (sz_vol_pos[0] NE 2) THEN $
  294.    Message, 'Vol_Pos must be a [3, 2] array.'
  295. IF (sz_vol_pos[1] NE 3) THEN $
  296.    Message, 'Vol_Pos must be a [3, 2] array.'
  297. IF (sz_vol_pos[2] NE 2) THEN $
  298.    Message, 'Vol_Pos must be a [3, 2] array.'
  299. vol_pos1 = Float(vol_pos)
  300. IF (vol_pos[0, 0] EQ vol_pos[0, 1]) THEN $
  301.    Message, 'Vol_Pos contains invalid X coordinates.'
  302. IF (vol_pos[1, 0] EQ vol_pos[1, 1]) THEN $
  303.    Message, 'Vol_Pos contains invalid Y coordinates.'
  304. IF (vol_pos[2, 0] EQ vol_pos[2, 1]) THEN $
  305.    Message, 'Vol_Pos contains invalid Z coordinates.'
  306. vpx1 = vol_pos[0, 0] < vol_pos[0, 1]
  307. vpy1 = vol_pos[1, 0] < vol_pos[1, 1]
  308. vpz1 = vol_pos[2, 0] < vol_pos[2, 1]
  309. vpx2 = vol_pos[0, 0] > vol_pos[0, 1]
  310. vpy2 = vol_pos[1, 0] > vol_pos[1, 1]
  311. vpz2 = vol_pos[2, 0] > vol_pos[2, 1]
  312.  
  313. sz_img_ref = Size(img_ref)
  314. IF (sz_img_ref[0] NE 2) THEN $
  315.    Message, 'Img_Ref must be a [2, n] array.'
  316. IF (sz_img_ref[1] NE 2) THEN $
  317.    Message, 'Img_Ref must be a [2, n] array.'
  318. IF (sz_img_ref[2] NE frames) THEN $
  319.    Message, 'Img_Ref must be a [2, n] array, where n is the number of images.'
  320. img_ref1 = Float(img_ref)
  321.  
  322. sz_img_mag = Size(img_mag)
  323. IF (sz_img_mag[0] NE 2) THEN $
  324.    Message, 'Img_Mag must be a [2, n] array.'
  325. IF (sz_img_mag[1] NE 2) THEN $
  326.    Message, 'Img_Mag must be a [2, n] array.'
  327. IF (sz_img_mag[2] NE frames) THEN $
  328.    Message, 'Img_Mag must be a [2, n] array, where n is the number of images.'
  329. ind = Where(img_mag[*] LT 1)
  330. IF (ind[0] GE 0L) THEN $
  331.    Message, 'All elements in Img_Mag must be >= 1.'
  332. img_mag1 = Float(img_mag)
  333.  
  334. IF (N_Elements(vol_size) NE 3) THEN $
  335.    Message, 'Vol_size must contain 3 elements.'
  336. vol_size1 = Long(Abs(vol_size[*]))
  337.  
  338. ; *** Check keywords.
  339.  
  340. miss = 0B
  341. IF (N_Elements(missing) GT 0L) THEN miss = Byte(missing[0])
  342.  
  343. eval_mode = 0
  344. IF (N_Elements(mode) GT 0L) THEN eval_mode = Fix(mode[0])
  345.  
  346. ; *** Set up variables.
  347.  
  348. vx = vol_size1[0]
  349. vy = vol_size1[1]
  350. vz = vol_size1[2]
  351. vxm1 = vx - 1
  352. vym1 = vy - 1
  353. vzm1 = vz - 1
  354.  
  355. ; *** Cell coordinates.
  356. rx = ((vpx2 - vpx1) * Findgen(vx) / Float(vxm1)) + vpx1
  357. ry = ((vpy2 - vpy1) * Findgen(vy) / Float(vym1)) + vpy1
  358. rz = ((vpz2 - vpz1) * Findgen(vz) / Float(vzm1)) + vpz1
  359. xplane = Reform((Temporary(rx) # Replicate(1.0, vy)), (vx * vy))
  360. yplane = Reform((Replicate(1.0, vx) # Temporary(ry)), (vx * vy))
  361. coords = [[Temporary(xplane)], [Temporary(yplane)], $
  362.           [Fltarr((vx * vy), /Nozero)], [Replicate(1.0, (vx * vy))]]
  363.  
  364. ; *** Save current view matrix.
  365. save_t3d = !P.T
  366.  
  367. ; *** Create the volume.
  368. IF (eval_mode GT 0) THEN vol = Bytarr(vx, vy, vz)
  369. IF (eval_mode EQ 0) THEN vol = Intarr(vx, vy, vz)
  370. IF (eval_mode LT 0) THEN vol = Replicate(255B, vx, vy, vz)
  371.  
  372. FOR j=0, (frames-1) DO BEGIN
  373.    ; *** Set up transform.
  374.    T3d, /Reset
  375.    T3d, Rotate=[obj_rot1[0, j], 0.0, 0.0]
  376.    T3d, Rotate=[0.0, obj_rot1[1, j], 0.0]
  377.    T3d, Rotate=[0.0, 0.0, obj_rot1[2, j]]
  378.    T3d, Translate=obj_pos1[*, j]
  379.    IF (focal1[j] GT 0.0) THEN BEGIN
  380.       T3d, Translate=[0.0, 0.0, -dist1[j]]
  381.       T3d, Perspective=$
  382.            ((focal1[j] / obj_pos1[2, j]) * (obj_pos1[2, j] - dist1[j]))
  383.    ENDIF
  384.    T3d, Scale=[img_mag1[0, j], img_mag1[1, j], 1.0]
  385.    T3d, Translate=[img_ref1[0, j], img_ref1[1, j], 0.0]
  386.  
  387.    ; *** Fill in the volume one plane at a time.
  388.    FOR i=0, vzm1 DO BEGIN
  389.       coords[0, 2] = Replicate(rz[i], (vx * vy))
  390.       plane_index = coords # !P.T
  391.       vol_x  = plane_index[*, 0] / plane_index[*, 3]
  392.       vol_y  = plane_index[*, 1] / plane_index[*, 3]
  393.  
  394.       IF (eval_mode LT 0) THEN $
  395.          vol[0, 0, i] = vol[*, *, i] < $
  396.             Interpolate(images[*, *, j], vol_x, vol_y, Missing=miss, $
  397.                         Cubic=Keyword_Set(cubic))
  398.  
  399.       IF (eval_mode GT 0) THEN $
  400.          vol[0, 0, i] = vol[*, *, i] > $
  401.             Interpolate(images[*, *, j], vol_x, vol_y, Missing=miss, $
  402.                         Cubic=Keyword_Set(cubic))
  403.  
  404.       IF (eval_mode EQ 0) THEN $
  405.          vol[0, 0, i] = vol[*, *, i] + $
  406.             Fix(Interpolate(images[*, *, j], vol_x, vol_y, Missing=miss, $
  407.                             Cubic=Keyword_Set(cubic)))
  408.  
  409.    ENDFOR
  410.    Print, 'Completed image ' + String(j+1)
  411. ENDFOR
  412.  
  413. IF (eval_mode EQ 0) THEN vol = Byte(vol / frames)
  414.  
  415. ; *** Restore view matrix.
  416. !P.T = save_t3d
  417.  
  418. RETURN, vol
  419. END
  420.